package com.sheledon.flyCat.core.factory;

import com.sheledon.flyCat.annotation.springmvc.GetMapping;
import com.sheledon.flyCat.annotation.springmvc.PostMapping;
import com.sheledon.flyCat.annotation.springmvc.RestController;
import com.sheledon.flyCat.common.pojo.MethodDetail;
import com.sheledon.flyCat.factory.ClassFactory;
import com.sheledon.flyCat.network.socket.http.enum_.HttpMethod;
import lombok.extern.slf4j.Slf4j;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;


/**
 * 实现 @PathVariable 关键在这里！！！！
 */
@Slf4j
public class RequestRouteMapper {
    private final static HttpMethod [] HTTP_METHODS = new HttpMethod[]{HttpMethod.GET,HttpMethod.POST};
    // formatUrl -----> targetMethod
    public final static Map<HttpMethod,Map<String,Method>> REQUEST_ROUTE_MAP =new HashMap<>();
    // 通过originalUrl实现正确的赋值操作
    // formatUrl -----> originalUrl
    public final static Map<HttpMethod,Map<String,String>> REQUEST_URL_MAP =new HashMap<>();
    static {
        for (HttpMethod hm: HTTP_METHODS){
            REQUEST_ROUTE_MAP.put(hm,new HashMap<>());
            REQUEST_URL_MAP.put(hm,new HashMap<>());
        }
    }
    public static void loadAllRoutes(){
        ClassFactory.CLASS_FACTORY.get(RestController.class).forEach(RequestRouteMapper::loadRoute);
    }
    private static void loadRoute(Class<?> clazz){
        String basePath = clazz.getAnnotation(RestController.class).value();
        Method[] methods = clazz.getDeclaredMethods();
        for (Method method : methods){
            if (method.isAnnotationPresent(GetMapping.class)){
                GetMapping annotation = method.getAnnotation(GetMapping.class);
                mapUrlToMethod(basePath+annotation.value(),HttpMethod.GET,method);
            }
            if (method.isAnnotationPresent(PostMapping.class)){
                PostMapping annotation = method.getAnnotation(PostMapping.class);
                mapUrlToMethod(basePath+annotation.value(),HttpMethod.POST,method);
            }
        }
    }
    private static void mapUrlToMethod(String url,HttpMethod httpMethod,Method targetMethod){
        String formatUrl = getFormatUrl(url);
        if (REQUEST_ROUTE_MAP.get(httpMethod).containsKey(formatUrl)){
            throw new IllegalArgumentException(String.format("duplicate url: %s", url));
        }
        REQUEST_ROUTE_MAP.get(httpMethod).put(formatUrl,targetMethod);
        REQUEST_URL_MAP.get(httpMethod).put(formatUrl,url);
    }
    private static String getFormatUrl(String url){
        String originPattern = url.replaceAll("\\{\\S*?}", "[\\\\u4e00-\\\\u9fa5_a-zA-Z0-9]+");
        String pattern = "^"+originPattern+"/?$";
        return pattern.replaceAll("/{2,}","/");
    }

    public static MethodDetail getMethodDetail(HttpMethod httpMethod,String requestPath){
        MethodDetail methodDetail = new MethodDetail();
        methodDetail.build(requestPath,REQUEST_ROUTE_MAP.get(httpMethod),REQUEST_URL_MAP.get(httpMethod));
        return methodDetail;
    }
}
